package impl.agentt;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.logging.Logger;

import debug.message.AgentDebugText;

import message.EnvoieHesitation;
import message.PartageNum;
import message.RefuseHesitation;
import message.SudoEMessage;
import message.ValideHesitation;
import fr.irit.smac.may.lib.components.messaging.receiver.AgentRef;
import fr.irit.smac.may.lib.interfaces.Push;
import fr.irit.smac.may.lib.pmbehaviour.PatternMatchingBehavior;
import sudoemerg.Behaviour;

public class BehaviourImpl extends Behaviour {
	int limiteBoucleInfinie = 2000;
	int valeur = 0;
	int hesitation = 0;
	int hesitIncr = 0;
	int criticite = 0;
	boolean certitude = false;
	ArrayList<AgentRef> refVoisins = new ArrayList<AgentRef>();
	ArrayList<AgentRef> refVoisinsAccept = new ArrayList<AgentRef>();
	ArrayList<Integer> listePossible = new ArrayList<Integer>();
	PatternMatchingBehavior pmb = new PatternMatchingBehavior(this);
	
	public void caseInitAgent() {
		valeur = info().getNum();
		if(valeur!=0)
			certitude = true;
		else
			for(int i=1;i<10;listePossible.add(i),i++);
		refVoisins = info().getListeVoisins();
		debugText("Init : %s - val = %s",myRef().pull().getName(),valeur);
		if(certitude)
			partage();
		else {
			criticite = listePossible.size();
			hesitation = listePossible.get(hesitIncr);
			recherche();
		}
	}
	
	public void partage() {
		debugText("Passage en mode partage, ma valeur : %s",valeur);
		debugText("Mes voisins : %s",refVoisins.toString());
		Iterator<AgentRef> iteVoi = refVoisins.iterator();
		while(iteVoi.hasNext()) {
			send().send(new PartageNum(myRef().pull(),valeur),iteVoi.next());
		}
		debugText("Ma mission est finie, adieu!");
		die().doIt();
	}
	
	public void recherche() {
		if(limiteBoucleInfinie>0) {
			debugText("Passage en mode recherche, mon hesitation : %s",hesitation);
			Iterator<AgentRef> iteVoi = refVoisins.iterator();
			while(iteVoi.hasNext()) {
				send().send(new EnvoieHesitation(myRef().pull(), hesitation, criticite),iteVoi.next());
			}
			limiteBoucleInfinie--;
			if(limiteBoucleInfinie==0)
				debugText("Limite atteinte!");
		}
	}
	
	public void casePartageNum(AgentRef exp,Integer num) {
		debugText("L'agent %s partage avec moi sa valeur : %s",exp.getName(),num);
		
		//Retirer de la liste des voisins
		refVoisins.remove(exp);
		
		if(!certitude) {
			for(int i=0;i<listePossible.size();i++) {
				if(listePossible.get(i)==num) {
					listePossible.remove(i);
					criticite = listePossible.size();
					break;
				}
			}
			if(listePossible.size()==1) {
				certitude=true;
				valeur = listePossible.get(0);
				debugText("J'ai trouve ma valeur : %s, je l'enregistre",valeur);
				info().setNum(valeur);
				partage();
			} else {
				debugText("Il me reste %s valeurs possible",listePossible.size());
				debugText("Valeurs possible : %s",listePossible.toString());
				if(hesitation==num) {
					hesitIncr = 0;
					hesitation = listePossible.get(hesitIncr);
					recherche();
				}
			}
		}
	}
	
	public void caseEnvoieHesitation(AgentRef exp, Integer hesit, Integer crit) {
		//debugText("L'agent %s partage avec moi son hesitation : %s",exp.getName(),hesit);
		if(hesit!=hesitation) {
			send().send(new ValideHesitation(myRef().pull(), hesit),exp);
		} else {
			if(criticite>crit) {
				hesitIncr = (hesitIncr+1) % listePossible.size();
				hesitation = listePossible.get(hesitIncr);
				refVoisinsAccept = new ArrayList<AgentRef>();
				recherche();
			} else {
				send().send(new RefuseHesitation(myRef().pull(), hesit),exp);
			}
		}
	}
	
	public void caseValideHesitation(AgentRef exp, Integer monHesit) {
		if(monHesit==hesitation && !certitude) {
			refVoisinsAccept.add(exp);
			if(refVoisinsAccept.containsAll(refVoisins)) {
				valeur = hesitation;
				certitude = true;
				partage();
			}
		}
	}
	
	public void caseRefuseHesitation(AgentRef exp, Integer hesit) {
		if(!certitude) {
			hesitIncr = (hesitIncr+1) % listePossible.size();
			hesitation = listePossible.get(hesitIncr);
			refVoisinsAccept = new ArrayList<AgentRef>();
			//criticite--;
			recherche();
		}
	}

	public void defaultCase(Object message) {
		Logger log = Logger.getLogger("alerte");
		log.info("Alerte par "+this.getClass().getCanonicalName()+" : Incomprehension du message "+message.getClass().getCanonicalName());
	}
	
	@Override
	protected Push<SudoEMessage> cycle() {
		// TODO Auto-generated method stub
		return new Push<SudoEMessage>() {
			public void push(SudoEMessage message) {
				pmb.match(message);
			}

		};
	}
	
	protected void debugText(String s , Object... params){
		if(debug().isDebugON()){
			debug().sendDebugMessage(new AgentDebugText(myRef().pull(),String.format(s, params)));
		}
	}

}
